#region Copyright Jonathan Quiros

//	
// All rights are reserved. Reproduction or transmission in whole or in 
// part, in any form or by any means, electronic, mechanical or otherwise, 
// is prohibited without the prior written consent of the copyright owner.
//
// Filename: UsersRepository.cs
//

#endregion

using System;
using System.Linq;
using System.Collections.Generic;
using Ids.Web.Listing;
using Novagoal.Models;
using Novagoal.Models.Utils;
using Novagoal.Repositories.Extensions;

namespace Novagoal.Repositories.Entities
{
    public class GamesRepository : BaseRepository, IGamesRepository
    {
        #region CONSTANTS



        #endregion

        #region PROPERTIES

        

        #endregion

        #region PUBLIC METHODS

        public List<Game> GetGames(Dictionary<GameListFilter, string> filterList, GameListSortField sortField, SortDirectionType sortDirection, int currentPage, int pageSize)
        {
            var qryGames = FilterGames(filterList);

            var users = SortGames(qryGames, sortField, sortDirection)
                .TakePage(currentPage, pageSize)
                .AsEnumerable()
                .Select(CreateGame)
                .ToList();

            return users;
        }

        public int GetTotalGames(Dictionary<GameListFilter, string> filterList)
        {
            return FilterGames(filterList).Count();
        }

        public IEnumerable<Game> GetUpcomingGamesByTournament(int tournamentId)
        {
            return EntitiesContext.games
                .Where(g => g.tournaments.id == tournamentId && g.started_at > UniversalDate && g.enabled)
                .Select(CreateGame)
                .OrderBy(g => g.StartedAt)
                .ToList();
        }

        public IEnumerable<Game> GetFinishedGamesByTournament(int tournamentId)
        {
            return EntitiesContext.games
                .Where(g => g.tournaments.id == tournamentId && g.started_at < UniversalDate)
                .Select(CreateGame)
                .OrderBy(g => g.StartedAt)
                .ToList();
        }

        public Result GetResultByPerson(int gameId, int personId)
        {
            return EntitiesContext.results
                .Where(r => r.games.id == gameId && r.people.id == personId)
                .Select(CreateResult)
                .FirstOrDefault();
        }

        public void SaveResult(int gameId, Result result)
        {
            var newResult = new results
                                {
                                    created_at = UniversalDate,
                                    games = EntitiesContext.games.Where(g => g.id == gameId).FirstOrDefault(),
                                    people = EntitiesContext.people.Where(p => p.id == result.UpdatedBy).FirstOrDefault(),
                                    points = result.Points,
                                    team_a_score = result.TeamAScore,
                                    team_b_score = result.TeamBScore,
                                    updated_at = UniversalDate,
                                    updated_by = result.UpdatedBy,
                                    players = EntitiesContext.players.Where(p => p.id == result.Player.Id).FirstOrDefault()
                                };
            EntitiesContext.AddToresults(newResult);
            EntitiesContext.SaveChanges();
        }

        public void DeleteResult(int gameId, int updatedBy)
        {
            var oldResult = EntitiesContext.results
                .Where(r => r.games.id == gameId && r.people.id == updatedBy)
                .FirstOrDefault();

            if (oldResult != null)
            {
                EntitiesContext.DeleteObject(oldResult);
                EntitiesContext.SaveChanges();
            }
        }

        public Game GetGame(int gameId)
        {
            return EntitiesContext.games
                .Where(g => g.id == gameId)
                .Select(CreateGame)
                .FirstOrDefault();
        }

        public List<Player> GetPlayersByTeam(int teamId)
        {
            return EntitiesContext.players_teams
                .Where(pt => pt.teams.id == teamId && pt.enabled)
                .Select(pt => pt.players)
                .Select(CreatePlayer)
                .ToList();

            //return EntitiesContext.players
            //    .Where(p => p.teams.id == teamId)
            //    .Select(CreatePlayer)
            //    .ToList();
        }

        public int AddGame(Game game)
        {
            var gameEntity = new games
                                 {
                                     created_at = UniversalDate,
                                     updated_at = UniversalDate,
                                     updated_by = game.UpdatedBy,
                                     teamsA = EntitiesContext.teams.Where(t => t.id == game.TeamA.Id).FirstOrDefault(),
                                     teamsB = EntitiesContext.teams.Where(t => t.id == game.TeamB.Id).FirstOrDefault(),
                                     tournaments = EntitiesContext.tournaments.Where(t => t.id == game.Tournament.Id).FirstOrDefault(),
                                     started_at = game.StartedAt,
                                     enabled = game.Enabled,
                                 };
            EntitiesContext.AddTogames(gameEntity);
            EntitiesContext.SaveChanges();
            return gameEntity.id;
        }

        public int EditGame(Game game)
        {
            var gameEntity = EntitiesContext.games.Where(g => g.id == game.Id).FirstOrDefault();
            gameEntity.tournaments = EntitiesContext.tournaments.Where(t => t.id == game.Tournament.Id).FirstOrDefault();
            gameEntity.teamsA = EntitiesContext.teams.Where(t => t.id == game.TeamA.Id).FirstOrDefault();
            gameEntity.teamsB = EntitiesContext.teams.Where(t => t.id == game.TeamB.Id).FirstOrDefault();
            gameEntity.started_at = game.StartedAt;
            gameEntity.updated_by = game.UpdatedBy;
            gameEntity.enabled = game.Enabled;

            EntitiesContext.SaveChanges();
            return gameEntity.id;
        }

        public IEnumerable<Person> GetPeopleWithResult(int gameId)
        {
            return EntitiesContext.results
                .Where(r => r.games.id == gameId)
                .Select(r => r.people)
                .Select(CreatePerson)
                .ToList();
        }

        public void UpdatePoints(Result result, Game game, Person person)
        {
            var entity = EntitiesContext.results
                .Where(r => r.id == result.Id)
                .FirstOrDefault();

            entity.points = result.Points;
            EntitiesContext.SaveChanges();

            var tournamentId = EntitiesContext.games.Where(g => g.id == game.Id).Select(g => g.tournaments.id).FirstOrDefault();

            var personParty = EntitiesContext.parties_people
                .Where(pp => pp.people.id == person.Id && pp.parties.tournaments.id == tournamentId)
                .ToList();
            foreach (var partiesPeople in personParty)
            {
                partiesPeople.total_points += result.Points;
            }
            EntitiesContext.SaveChanges();
        }

        public void CloseGame(int gameId)
        {
            var gameEntity = EntitiesContext.games
                .Where(g => g.id == gameId)
                .FirstOrDefault();
            gameEntity.enabled = false;
            EntitiesContext.SaveChanges();
        }

        public List<Game> GetGamesByTeam(int teamId)
        {
            return EntitiesContext.games
                .Where(g => g.teamsA.id == teamId || g.teamsB.id == teamId)
                .Select(CreateGame)
                .OrderByDescending(g => g.StartedAt)
                .ToList();
        }

        #endregion

        #region PRIVATE METHODS

        private IQueryable<games> FilterGames(Dictionary<GameListFilter, string> filters)
        {
            var games = EntitiesContext.games as IQueryable<games>;

            if (filters != null)
            {
                if (filters.Keys.Contains(GameListFilter.Id))
                {
                    int id;
                    if (int.TryParse(filters[GameListFilter.Id], out id))
                    {
                        return games.Where(item => item.id == id);
                    }
                }
                if (filters.Keys.Contains(GameListFilter.TeamA))
                {
                    var strTeamA = filters[GameListFilter.TeamA];
                    games = games.Where(item => item.teamsA.name.Contains(strTeamA));
                }
                if (filters.Keys.Contains(GameListFilter.TeamB))
                {
                    var strTeamB = filters[GameListFilter.TeamB];
                    games = games.Where(item => item.teamsB.name.Contains(strTeamB));
                }
                if (filters.Keys.Contains(GameListFilter.Tournament))
                {
                    var strTournament = filters[GameListFilter.Tournament];
                    games = games.Where(item => item.tournaments.name.Contains(strTournament));
                }
            }

            return games;
        }

        private static IQueryable<games> SortGames(IQueryable<games> query, GameListSortField sortField, SortDirectionType sortDirection)
        {
            switch (sortField)
            {
                case GameListSortField.Id:
                    return query.OrderBy(item => item.id, sortDirection);

                case GameListSortField.TeamA:
                    return query.OrderBy(item => item.teamsA.name, sortDirection);

                case GameListSortField.TeamB:
                    return query.OrderBy(item => item.teamsB, sortDirection);

                case GameListSortField.Tournament:
                    return query.OrderBy(item => item.tournaments.name, sortDirection);

                case GameListSortField.StartAt:
                    return query.OrderBy(item => item.started_at, sortDirection);

                case GameListSortField.CreatedAt:
                    return query.OrderBy(item => item.created_at, sortDirection);

                case GameListSortField.UpdatedAt:
                    return query.OrderBy(item => item.updated_at, sortDirection);

            }
            return query.OrderByDescending(item => item.id);
        }

        #endregion
    }
}